import React, { useReducer, useState } from "react";
import { useContext } from "react";
import loaderContext from "../loader/LoaderContext";
import { UserContext } from "./userContext";
import {
  getStorageToken,
  isGivenTokenEmpty,
  isGivenTokenExpired,
  isGivenTokenExpiring,
  isGivenTokenInvalid,
} from "../../services/tokenService";

import jwtDecode from "jwt-decode";
import { UserProfile, UserPrivileges } from "../../services/authService";
import {
  getAssignablePermissions,
  transformAssignablePermissions,
} from "../../services/permissionService";

import {
  getHasMultipleBrands,
  getIsSelf,
  getIsPrimaryBrand,
  removeAccessToken,
  removeHasMultipleBrands,
  removeIsPrimaryBrand,
  removeIsSelf,
  getCorpBrandCode,
} from "../../services/localstorageService";
import { getEntityUrl } from "../../services/entityService";
import { dashboardNames, entityNames } from "../../constants/enums";
import { useNavigate } from "react-router-dom";
const baseUserObject = {
  email: "",
  exp: 0,
  role: [],
  iat: 0,
  iss: "",
  jti: "",
  nbf: 0,
  sub: "",
  userProfile: null,
  linkData: null,
  privileges: null,
  distinctModules: [],
};
const reducer = (state, { type, payload }) => {
  switch (type?.toString().toLowerCase()) {
    case "login": {
  
      let userObject = { ...state.user, ...payload.decode };
      let returned = {
        user: {
          ...userObject,
          isAuthenticated: true,
          userProfile: payload.userProfile,
          linkData: null,
          privileges: payload.privileges,
          role: payload.role,
          distinctModules: payload.distinctModules,
        },
        token: payload.token,
      };

      return returned;
    }
    case "clear":
    case "logout": {
      let userObject = { ...state.user, ...baseUserObject };
      return {
        user: {
          ...userObject,
          isAuthenticated: false,
        },
        token: "",
      };
    }
    default:
      return state;
  }
};

export const UserProvider = ({ children }) => {
  const [waiting, setWaiting] = useState(-1);
  const { updateLoaderStatus } = useContext(loaderContext);

  const [state, dispatch] = useReducer(reducer, {
    user: baseUserObject,
    token: null,
  });

  const loadScriptsAndStyles = (clientName) => {
    let id = "scriptContainer";
    const container = document.getElementById(id);
    container.innerHTML = "";
    const script = document.createElement("script");
    script.type = "text/babel";
    script.src = `../../styles/${clientName}/js/common.js`;
    script.onload = function () {};
    script.onerror = function () {};
    container.appendChild(script);
  };

  const getProfileAndPrivileges = (
    token,
    hasMultipleBrands,
    isPrimaryBrand,
    isSelf,
    corpBrandCode,
    callbackMethod = null
  ) => {
    updateLoaderStatus(true);
    setWaiting(0);
    const decode = jwtDecode(token);
    UserProfile(decode.email).then(
      (userProfile) => {
      
        if (userProfile === undefined || userProfile === null) {
          logout();
        } else {
          UserPrivileges(userProfile.id).then(
          
            (userPrivileges) => {
            
              const set = () => {
                let role =
                  decode[
                    "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
                  ];

                let distinctModules = [];
                for (let c = 0; c < userPrivileges.length; c++) {
                  let privilege = userPrivileges[c];
                  let moduleName = privilege.moduleName;
                  let moduleDescription = privilege.moduleDescription;
                  const existing = distinctModules.find(
                    (x) => x.moduleName === moduleName
                  );
                  if (existing === null || existing === undefined) {
                    distinctModules.push({
                      moduleName: moduleName,
                      moduleDescription: moduleDescription,
                    });
                  }
                }
                userProfile.hasMultipleBrands = hasMultipleBrands;
                userProfile.isPrimaryBrand = isPrimaryBrand;
                userProfile.isSelf = isSelf;
                userProfile.corpBrandCode = corpBrandCode;
                let payload = {
                  distinctModules: distinctModules,
                  role: role,
                  userProfile: userProfile,
                  privileges: userPrivileges,
                  token: token,
                };
                dispatch({ type: "login", payload: payload });
                loadScriptsAndStyles(userProfile.brandID);
                if (callbackMethod !== null) {
                  callbackMethod();
                }
                updateLoaderStatus(false);
                setWaiting(1);
              };
              set();
            },
            (error) => {
              updateLoaderStatus(false);
              setWaiting(1);
            }
          );
        }
      },
      (error) => {
        updateLoaderStatus(false);
        setWaiting(1);
      }
    );
  };

  const replaceUrl = (dashboard, softReplace = false) => {
    let entityName = null;
    switch (dashboard) {
      case dashboardNames.GROUPS:{
        entityName = entityNames.GROUPMANAGEMENT;
        break;
      }
      case dashboardNames.ROLES:{
        entityName = entityNames.ROLEMANAGEMENT;
        break;
      }
      case dashboardNames.USERS:{
        entityName = entityNames.USERMANAGEMENT;
        break;
      }
      case dashboardNames.HOURSOPERATION:{
        entityName = entityNames.HOURSOPERATION;
        break;
      }
      default: {
        entityName = "";
        break;
      }
    }
    let url = getEntityUrl(entityName);
    if (softReplace === false) {
      window.location.replace(url);
    } else {
      window.history.replaceState(null, "", url);
    }
  };

   const removeAll = () => {
    /*dispatch({ type: "clear", payload: {} });*/
    removeAccessToken();
    /*
    removeHasMultipleBrands();
    removeIsPrimaryBrand();
    removeIsSelf();*/
  };
  const navigate = useNavigate();
   const logout = (redirect = true) => {
    removeAll();
    //dispatch({ type: "logout", payload: {} });
    updateLoaderStatus(false);
    if (redirect === true) {
      navigate("/logout");
    }
  };

   const getTokenDetails = () => {
    let token = getStorageToken();
    let isInValid = false;
    let isExpired = false;
    let isExpiring = false;
    if (
      isGivenTokenInvalid(token) === true ||
      isGivenTokenEmpty(token) === true
    ) {
      isInValid = true;
    } else {
      isExpired = isGivenTokenExpired(token);
      isExpiring = isGivenTokenExpiring(token);
    }
    return {
      token,
      isInValid,
      isExpired,
      isExpiring,
    };
  };

  const getBrandSpecificOptions = () => {
    let hasMultipleBrands = getHasMultipleBrands();
    let isPrimaryBrand = getIsPrimaryBrand();
    let isSelf = getIsSelf();
    let corpBrandCode = getCorpBrandCode();
    return { hasMultipleBrands, isPrimaryBrand, isSelf, corpBrandCode };
  };
  return (
    <UserContext.Provider
      value={{
        state,
        getProfileAndPrivileges,
        removeAll,
        logout,
        waiting,
        getTokenDetails,
        getBrandSpecificOptions,
        replaceUrl,
      }}
    >
      {children}
    </UserContext.Provider>
  );
};
